---
title: "Kotlin 常見陷阱與解決方案"
description: "了解常見的 Kotlin 陷阱及其解決方案，並與 JavaScript 開發模式進行比較"
---

# Kotlin 常見陷阱與解決方案

歡迎來到 JavaScript 到 Kotlin 轉換的第十二個模組！在本模組中，我們將探討從 JavaScript 過渡到 Kotlin 時開發人員遇到的常見陷阱，並學習避免這些陷阱的有效解決方案。我們將涵蓋協程編程陷阱、空安全問題、效能優化錯誤和記憶體管理問題。

## 學習目標

在本模組結束時，您將能夠：
- 識別並避免常見的 Kotlin 編程陷阱
- 理解協程編程陷阱和解決方案
- 正確處理空安全問題
- 避免效能優化錯誤
- 管理記憶體洩漏和資源清理
- 應用錯誤處理的最佳實踐
- 有效偵錯常見的 Kotlin 問題

## 協程編程陷阱

### 常見的協程錯誤

<UniversalEditor title="協程編程陷阱" compare={true}>
```javascript !! js
// JavaScript async/await 陷阱
class UserService {
  constructor() {
    this.users = [];
  }
  
  // 陷阱 1：未正確處理錯誤
  async fetchUsers() {
    try {
      const response = await fetch('/api/users');
      const users = await response.json();
      this.users = users;
      return users;
    } catch (error) {
      console.error('取得使用者時出錯:', error);
      // 缺少錯誤處理 - 可能導致應用程式崩潰
    }
  }
  
  // 陷阱 2：未取消請求
  async searchUsers(query) {
    const response = await fetch(`/api/users?q=${query}`);
    const users = await response.json();
    return users;
    // 如果元件卸載，此請求將繼續
  }
  
  // 陷阱 3：競爭條件
  async updateUser(id, data) {
    const response = await fetch(`/api/users/${id}`, {
      method: 'PUT',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify(data)
    });
    return response.json();
    // 快速多次呼叫可能導致競爭條件
  }
  
  // 陷阱 4：阻塞主執行緒
  async processLargeData(data) {
    const result = [];
    for (const item of data) {
      const processed = await this.heavyProcessing(item);
      result.push(processed);
    }
    return result;
    // 這會阻塞主執行緒
  }
  
  // 陷阱 5：未使用正確的非同步模式
  async getUserWithOrders(userId) {
    const user = await this.fetchUser(userId);
    const orders = await this.fetchOrders(userId);
    return { ...user, orders };
    // 順序呼叫而非並行呼叫
  }
}
```

```kotlin !! kt
// Kotlin 協程陷阱與解決方案
class UserService {
    private val users = mutableListOf<User>()
    
    // 陷阱 1：未正確處理例外
    suspend fun fetchUsers(): List<User> {
        return try {
            val response = httpClient.get("/api/users")
            val users = Json.decodeFromString<List<User>>(response)
            this.users.clear()
            this.users.addAll(users)
            users
        } catch (e: Exception) {
            // 解決方案：使用自訂例外進行適當的錯誤處理
            throw UserFetchException("取得使用者失敗", e)
        }
    }
    
    // 陷阱 2：未使用結構化並行
    suspend fun searchUsers(query: String): List<User> {
        // 解決方案：使用帶取消功能的協程作用域
        return withContext(Dispatchers.IO) {
            val response = httpClient.get("/api/users?q=$query")
            Json.decodeFromString(response)
        }
    }
    
    // 陷阱 3：共享狀態中的競爭條件
    private val userCache = mutableMapOf<Long, User>()
    
    suspend fun updateUser(id: Long, data: UpdateUserRequest): User {
        // 解決方案：使用互斥鎖進行執行緒安全存取
        return userCacheMutex.withLock {
            val response = httpClient.put("/api/users/$id") {
                setBody(Json.encodeToString(data))
            }
            val user = Json.decodeFromString<User>(response)
            userCache[id] = user
            user
        }
    }
    
    // 陷阱 4：協程中的阻塞操作
    suspend fun processLargeData(data: List<DataItem>): List<ProcessedItem> {
        // 解決方案：對 CPU 密集型工作使用 withContext
        return withContext(Dispatchers.Default) {
            data.map { item ->
                heavyProcessing(item)
            }
        }
    }
    
    // 陷阱 5：順序執行而非並行執行
    suspend fun getUserWithOrders(userId: Long): UserWithOrders {
        // 解決方案：使用 async 進行並行執行
        return coroutineScope {
            val userDeferred = async { fetchUser(userId) }
            val ordersDeferred = async { fetchOrders(userId) }
            
            val user = userDeferred.await()
            val orders = ordersDeferred.await()
            
            UserWithOrders(user = user, orders = orders)
        }
    }
    
    // 解決方案：適當的協程作用域管理
    private val userCacheMutex = Mutex()
    
    // 解決方案：使用自訂例外進行更好的錯誤處理
    class UserFetchException(message: String, cause: Throwable? = null) : 
        Exception(message, cause)
}

// 協程使用最佳實踐
class CoroutineBestPractices {
    
    // 1. 使用結構化並行
    suspend fun structuredConcurrencyExample() = coroutineScope {
        val result1 = async { fetchData1() }
        val result2 = async { fetchData2() }
        
        // 如果任何協程失敗，所有協程都會被取消
        result1.await() + result2.await()
    }
    
    // 2. 正確處理取消
    suspend fun cancellationAwareOperation() {
        try {
            withTimeout(5000) {
                longRunningOperation()
            }
        } catch (e: TimeoutCancellationException) {
            // 處理逾時
            cleanup()
        }
    }
    
    // 3. 使用適當的調度器
    suspend fun dispatcherExample() {
        // IO 操作
        val data = withContext(Dispatchers.IO) {
            readFromFile()
        }
        
        // CPU 密集型操作
        val processed = withContext(Dispatchers.Default) {
            processData(data)
        }
        
        // UI 更新（在 Android 中）
        withContext(Dispatchers.Main) {
            updateUI(processed)
        }
    }
    
    // 4. 避免在協程中進行阻塞操作
    suspend fun nonBlockingExample() {
        // 而不是 Thread.sleep()
        delay(1000)
        
        // 而不是阻塞呼叫
        withContext(Dispatchers.IO) {
            // IO 操作
        }
    }
}
```
</UniversalEditor>

## 空安全陷阱

### 常見的空安全問題

<UniversalEditor title="空安全陷阱" compare={true}>
```javascript !! js
// JavaScript null/undefined 陷阱
class UserManager {
  constructor() {
    this.users = [];
  }
  
  // 陷阱 1：未檢查 null/undefined
  getUserName(userId) {
    const user = this.users.find(u => u.id === userId);
    return user.name; // 如果 user 是 undefined，可能會拋出錯誤
  }
  
  // 陷阱 2：不一致的 null 處理
  updateUser(userId, data) {
    const user = this.users.find(u => u.id === userId);
    if (user) {
      Object.assign(user, data);
    }
    // 如果未找到使用者，則無錯誤
  }
  
  // 陷阱 3：可選鏈濫用
  getNestedProperty(user) {
    return user?.profile?.address?.street;
    // 傳回 undefined 而不是拋出錯誤
  }
  
  // 陷阱 4：未正確使用預設值
  getDisplayName(user) {
    return user.name || 'Anonymous';
    // 假值（空字串、0）被取代
  }
  
  // 陷阱 5：使用 null 的陣列操作
  getActiveUsers() {
    return this.users.filter(user => user.active);
    // 可能包含 null/undefined 值
  }
}
```

```kotlin !! kt
// Kotlin 空安全陷阱與解決方案
class UserManager {
    private val users = mutableListOf<User>()
    
    // 陷阱 1：未正確使用空安全
    fun getUserName(userId: Long): String {
        val user = users.find { it.id == userId }
        return user.name // 編譯錯誤 - user 可能為 null
    }
    
    // 解決方案 1：安全呼叫運算子
    fun getUserNameSafe(userId: Long): String? {
        val user = users.find { it.id == userId }
        return user?.name
    }
    
    // 解決方案 2：使用 Elvis 運算子提供預設值
    fun getUserNameWithDefault(userId: Long): String {
        val user = users.find { it.id == userId }
        return user?.name ?: "Unknown User"
    }
    
    // 解決方案 3：對遺失使用者拋出例外
    fun getUserNameOrThrow(userId: Long): String {
        val user = users.find { it.id == userId }
            ?: throw UserNotFoundException("User not found: $userId")
        return user.name
    }
    
    // 陷阱 2：不一致的 null 處理
    fun updateUser(userId: Long, data: UpdateUserRequest) {
        val user = users.find { it.id == userId }
        if (user != null) {
            // 更新使用者
        }
        // 靜默失敗 - 不好
    }
    
    // 解決方案：適當的錯誤處理
    fun updateUserOrThrow(userId: Long, data: UpdateUserRequest) {
        val user = users.find { it.id == userId }
            ?: throw UserNotFoundException("User not found: $userId")
        
        // 更新使用者
    }
    
    // 陷阱 3：未使用智慧轉換
    fun processUser(user: User?) {
        if (user != null) {
            // 在某些情況下，user 在這裡仍然是可空的
            println(user.name) // 可能為 null
        }
    }
    
    // 解決方案：使用智慧轉換
    fun processUserSmart(user: User?) {
        if (user != null && user.name != null) {
            // user 現在保證非空，name 也非空
            println(user.name.length) // 安全存取
        }
    }
    
    // 陷阱 4：不安全的型別轉換
    fun processData(data: Any?): String {
        return data as String // 可能拋出 ClassCastException
    }
    
    // 解決方案：安全的型別轉換
    fun processDataSafe(data: Any?): String? {
        return data as? String
    }
    
    // 陷阱 5：未使用密封類別進行錯誤處理
    sealed class UserResult {
        data class Success(val user: User) : UserResult()
        data class Error(val message: String) : UserResult()
    }
    
    fun getUserResult(userId: Long): UserResult {
        return try {
            val user = users.find { it.id == userId }
                ?: return UserResult.Error("User not found")
            UserResult.Success(user)
        } catch (e: Exception) {
            UserResult.Error("Error fetching user: ${e.message}")
        }
    }
}

// 空安全最佳實踐
class NullSafetyBestPractices {
    
    // 1. 盡可能使用非空型別
    fun createUser(name: String, email: String): User {
        return User(
            name = name,
            email = email
        )
    }
    
    // 2. 僅在必要時使用可空型別
    fun createUserWithOptional(name: String, email: String, phone: String? = null): User {
        return User(
            name = name,
            email = email,
            phone = phone // 僅在真正可選時可空
        )
    }
    
    // 3. 使用安全呼叫運算子進行鏈式呼叫
    fun getStreetName(user: User?): String? {
        return user?.address?.street
    }
    
    // 4. 使用 let 進行空安全操作
    fun processUserIfNotNull(user: User?) {
        user?.let { safeUser ->
            // safeUser 在這裡保證非空
            processUser(safeUser)
        }
    }
    
    // 5. 使用 when 運算式進行 null 處理
    fun getDisplayName(user: User?): String {
        return when (user) {
            null -> "Unknown User"
            else -> user.name ?: "Anonymous"
        }
    }
}
```
</UniversalEditor>

## 效能優化陷阱

### 常見的效能錯誤

<UniversalEditor title="效能優化陷阱" compare={true}>
```javascript !! js
// JavaScript 效能陷阱
class PerformanceExample {
  constructor() {
    this.data = [];
  }
  
  // 陷阱 1：低效的陣列操作
  filterAndMapData() {
    return this.data
      .filter(item => item.active)
      .map(item => item.name)
      .filter(name => name.length > 0);
    // 多次陣列迭代
  }
  
  // 陷阱 2：閉包導致的記憶體洩漏
  createEventListeners() {
    this.data.forEach(item => {
      document.addEventListener('click', () => {
        console.log(item.name);
      });
    });
    // 事件監聽器未被移除
  }
  
  // 陷阱 3：同步操作阻塞主執行緒
  processLargeData(data) {
    const result = [];
    for (let i = 0; i < data.length; i++) {
      const processed = this.heavyProcessing(data[i]);
      result.push(processed);
    }
    return result;
    // 阻塞 UI 執行緒
  }
  
  // 陷阱 4：低效的物件建立
  createObjects() {
    const objects = [];
    for (let i = 0; i < 10000; i++) {
      objects.push({
        id: i,
        name: `Item ${i}`,
        timestamp: Date.now()
      });
    }
    return objects;
    // 建立大量物件
  }
  
  // 陷阱 5：未使用快取
  expensiveCalculation(input) {
    // 每次都重新計算
    return this.heavyComputation(input);
  }
}
```

```kotlin !! kt
// Kotlin 效能陷阱與解決方案
class PerformanceExample {
    private val data = mutableListOf<DataItem>()
    
    // 陷阱 1：低效的集合操作
    fun filterAndMapDataInefficient(): List<String> {
        return data
            .filter { it.active }
            .map { it.name }
            .filter { it.isNotEmpty() }
        // 多次集合迭代
    }
    
    // 解決方案：使用序列進行單次迭代
    fun filterAndMapDataEfficient(): List<String> {
        return data.asSequence()
            .filter { it.active }
            .map { it.name }
            .filter { it.isNotEmpty() }
            .toList()
    }
    
    // 陷阱 2：協程導致的記憶體洩漏
    private val scope = CoroutineScope(Dispatchers.Main)
    
    fun startDataProcessing() {
        scope.launch {
            while (true) {
                processData()
                delay(1000)
            }
        }
        // 協程從未被取消
    }
    
    // 解決方案：適當的協程作用域管理
    private var dataJob: Job? = null
    
    fun startDataProcessingSafe() {
        dataJob?.cancel() // 取消之前的作業
        dataJob = CoroutineScope(Dispatchers.Main).launch {
            while (isActive) {
                processData()
                delay(1000)
            }
        }
    }
    
    fun stopDataProcessing() {
        dataJob?.cancel()
    }
    
    // 陷阱 3：主執行緒中的阻塞操作
    fun processLargeDataBlocking(data: List<DataItem>): List<ProcessedItem> {
        return data.map { item ->
            heavyProcessing(item) // 阻塞主執行緒
        }
    }
    
    // 解決方案：使用協程進行背景處理
    suspend fun processLargeDataAsync(data: List<DataItem>): List<ProcessedItem> {
        return withContext(Dispatchers.Default) {
            data.map { item ->
                heavyProcessing(item)
            }
        }
    }
    
    // 陷阱 4：低效的物件建立
    fun createObjectsInefficient(): List<TestObject> {
        return (0..10_000).map { i ->
            TestObject(
                id = i,
                name = "Item $i",
                timestamp = System.currentTimeMillis()
            )
        }
    }
    
    // 解決方案：使用物件池或惰性初始化
    private val objectPool = mutableMapOf<Int, TestObject>()
    
    fun createObjectEfficient(id: Int): TestObject {
        return objectPool.getOrPut(id) {
            TestObject(
                id = id,
                name = "Item $id",
                timestamp = System.currentTimeMillis()
            )
        }
    }
    
    // 陷阱 5：未使用快取
    fun expensiveCalculation(input: Int): Int {
        return heavyComputation(input) // 每次都重新計算
    }
    
    // 解決方案：使用快取
    private val cache = mutableMapOf<Int, Int>()
    
    fun expensiveCalculationCached(input: Int): Int {
        return cache.getOrPut(input) {
            heavyComputation(input)
        }
    }
}

// 效能最佳實踐
class PerformanceBestPractices {
    
    // 1. 對大型集合使用序列
    fun processLargeCollection(data: List<Int>): List<String> {
        return data.asSequence()
            .filter { it > 0 }
            .map { it.toString() }
            .toList()
    }
    
    // 2. 使用惰性初始化
    private val expensiveResource by lazy {
        createExpensiveResource()
    }
    
    // 3. 對頻繁建立的物件使用物件池
    private val stringBuilderPool = mutableListOf<StringBuilder>()
    
    fun getStringBuilder(): StringBuilder {
        return if (stringBuilderPool.isNotEmpty()) {
            stringBuilderPool.removeAt(stringBuilderPool.lastIndex)
        } else {
            StringBuilder()
        }
    }
    
    fun returnStringBuilder(builder: StringBuilder) {
        builder.clear()
        stringBuilderPool.add(builder)
    }
    
    // 4. 使用適當的資料結構
    fun findUserById(users: List<User>, id: Long): User? {
        // 使用 Map 進行 O(1) 查找，而不是 O(n)
        return users.associateBy { it.id }[id]
    }
    
    // 5. 使用協程進行非同步操作
    suspend fun processDataAsync(data: List<DataItem>): List<ProcessedItem> {
        return withContext(Dispatchers.Default) {
            data.map { item ->
                processItem(item)
            }
        }
    }
}
```
</UniversalEditor>

## 記憶體管理陷阱

### 記憶體洩漏預防

<UniversalEditor title="記憶體管理陷阱" compare={true}>
```javascript !! js
// JavaScript 記憶體管理陷阱
class MemoryExample {
  constructor() {
    this.listeners = [];
    this.data = [];
  }
  
  // 陷阱 1：事件監聽器未被移除
  addEventListeners() {
    document.addEventListener('click', this.handleClick.bind(this));
    // 監聽器從未被移除
  }
  
  // 陷阱 2：循環引用
  createCircularReference() {
    const obj1 = { name: 'Object 1' };
    const obj2 = { name: 'Object 2' };
    obj1.ref = obj2;
    obj2.ref = obj1;
    // 循環引用阻止垃圾回收
  }
  
  // 陷阱 3：閉包中的大物件
  createClosureWithLargeData() {
    const largeData = new Array(1000000).fill('data');
    return function() {
      console.log(largeData.length);
    };
    // largeData 保留在記憶體中
  }
  
  // 陷阱 4：計時器未被清除
  startTimer() {
    this.timer = setInterval(() => {
      this.processData();
    }, 1000);
    // 計時器從未被清除
  }
  
  // 陷阱 5：DOM 引用未被清除
  cacheDOMElements() {
    this.elements = document.querySelectorAll('.item');
    // DOM 引用保留在記憶體中
  }
}
```

```kotlin !! kt
// Kotlin 記憶體管理陷阱與解決方案
class MemoryExample {
    private val listeners = mutableListOf<() -> Unit>()
    private val data = mutableListOf<DataItem>()
    
    // 陷阱 1：協程未被取消
    private var dataJob: Job? = null
    
    fun startDataProcessing() {
        dataJob = CoroutineScope(Dispatchers.Main).launch {
            while (true) {
                processData()
                delay(1000)
            }
        }
        // 作業從未被取消
    }
    
    // 解決方案：適當的協程生命週期管理
    fun startDataProcessingSafe() {
        dataJob?.cancel() // 取消之前的作業
        dataJob = CoroutineScope(Dispatchers.Main).launch {
            while (isActive) {
                processData()
                delay(1000)
            }
        }
    }
    
    fun cleanup() {
        dataJob?.cancel()
        listeners.clear()
        data.clear()
    }
    
    // 陷阱 2：強引用阻止垃圾回收
    private var strongReference: Any? = null
    
    fun createStrongReference(obj: Any) {
        strongReference = obj
        // obj 永遠不會被垃圾回收
    }
    
    // 解決方案：使用弱引用
    private val weakReferences = WeakHashMap<Any, String>()
    
    fun createWeakReference(obj: Any, value: String) {
        weakReferences[obj] = value
        // obj 可以被垃圾回收
    }
    
    // 陷阱 3：閉包中的大物件
    fun createClosureWithLargeData(): () -> Unit {
        val largeData = List(1_000_000) { "data" }
        return {
            println(largeData.size)
        }
        // largeData 保留在記憶體中
    }
    
    // 解決方案：使用惰性初始化或清除引用
    private val largeData by lazy {
        List(1_000_000) { "data" }
    }
    
    fun createClosureSafe(): () -> Unit {
        return {
            println(largeData.size)
        }
    }
    
    // 陷阱 4：資源洩漏
    private var fileInputStream: FileInputStream? = null
    
    fun readFile(path: String): String {
        fileInputStream = FileInputStream(path)
        return fileInputStream!!.readBytes().toString()
        // FileInputStream 從未關閉
    }
    
    // 解決方案：使用 use 函式進行自動資源管理
    fun readFileSafe(path: String): String {
        return FileInputStream(path).use { input ->
            input.readBytes().toString()
        }
    }
    
    // 陷阱 5：觀察者未被移除
    private val observers = mutableListOf<Observer>()
    
    fun addObserver(observer: Observer) {
        observers.add(observer)
        // 觀察者從未被移除
    }
    
    // 解決方案：適當的觀察者生命週期管理
    fun addObserverSafe(observer: Observer) {
        observers.add(observer)
    }
    
    fun removeObserver(observer: Observer) {
        observers.remove(observer)
    }
    
    fun cleanup() {
        observers.clear()
    }
}

// 記憶體管理最佳實踐
class MemoryManagementBestPractices {
    
    // 1. 使用結構化並行
    suspend fun structuredConcurrencyExample() = coroutineScope {
        val job1 = launch { processData1() }
        val job2 = launch { processData2() }
        
        // 當作用域被取消時，所有作業都會被取消
        job1.join()
        job2.join()
    }
    
    // 2. 使用資源管理
    fun readFileWithResource(path: String): String {
        return File(path).inputStream().use { input ->
            input.bufferedReader().readText()
        }
    }
    
    // 3. 使用弱引用進行快取
    private val cache = WeakHashMap<String, ExpensiveObject>()
    
    fun getExpensiveObject(key: String): ExpensiveObject {
        return cache.getOrPut(key) {
            createExpensiveObject()
        }
    }
    
    // 4. 完成後清除引用
    class DataProcessor {
        private var data: List<DataItem>? = null
        
        fun processData(newData: List<DataItem>) {
            data = newData
            // 處理資料
        }
        
        fun cleanup() {
            data = null // 清除引用
        }
    }
    
    // 5. 對頻繁建立的物件使用物件池
    private val stringBuilderPool = mutableListOf<StringBuilder>()
    
    fun getStringBuilder(): StringBuilder {
        return if (stringBuilderPool.isNotEmpty()) {
            stringBuilderPool.removeAt(stringBuilderPool.lastIndex)
        } else {
            StringBuilder()
        }
    }
    
    fun returnStringBuilder(builder: StringBuilder) {
        builder.clear()
        stringBuilderPool.add(builder)
    }
}
```
</UniversalEditor>

## 錯誤處理陷阱

### 常見的錯誤處理錯誤

<UniversalEditor title="錯誤處理陷阱" compare={true}>
```javascript !! js
// JavaScript 錯誤處理陷阱
class ErrorExample {
  // 陷阱 1：吞掉例外
  async fetchData() {
    try {
      const response = await fetch('/api/data');
      const data = await response.json();
      return data;
    } catch (error) {
      console.log('發生錯誤');
      // 例外被吞掉，沒有重新拋出
    }
  }
  
  // 陷阱 2：通用的錯誤處理
  processData(data) {
    try {
      return this.heavyProcessing(data);
    } catch (error) {
      console.error('發生錯誤:', error);
      // 通用的錯誤訊息
    }
  }
  
  // 陷阱 3：未處理非同步錯誤
  async processAsyncData() {
    const promises = [this.fetchData1(), this.fetchData2()];
    const results = await Promise.all(promises);
    return results;
    // 如果任何 promise 被拒絕，整個操作都會失敗
  }
  
  // 陷阱 4：不一致的錯誤型別
  validateUser(user) {
    if (!user.name) {
      throw 'Name is required';
    }
    if (!user.email) {
      throw new Error('Email is required');
    }
    // 混合的錯誤型別
  }
  
  // 陷阱 5：未提供上下文
  async updateUser(userId, data) {
    try {
      const response = await fetch(`/api/users/${userId}`, {
        method: 'PUT',
        body: JSON.stringify(data)
      });
      return response.json();
    } catch (error) {
      throw new Error('Update failed');
      // 遺失了原始錯誤上下文
    }
  }
}
```

```kotlin !! kt
// Kotlin 錯誤處理陷阱與解決方案
class ErrorExample {
    
    // 陷阱 1：吞掉例外
    suspend fun fetchData(): List<DataItem>? {
        return try {
            val response = httpClient.get("/api/data")
            Json.decodeFromString(response)
        } catch (e: Exception) {
            println("發生錯誤")
            null // 例外被吞掉
        }
    }
    
    // 解決方案：使用自訂例外進行適當的錯誤處理
    suspend fun fetchDataSafe(): List<DataItem> {
        return try {
            val response = httpClient.get("/api/data")
            Json.decodeFromString(response)
        } catch (e: Exception) {
            throw DataFetchException("取得資料失敗", e)
        }
    }
    
    // 陷阱 2：通用的錯誤處理
    fun processData(data: List<DataItem>): List<ProcessedItem> {
        return try {
            data.map { item ->
                heavyProcessing(item)
            }
        } catch (e: Exception) {
            println("發生錯誤: $e")
            emptyList() // 通用處理
        }
    }
    
    // 解決方案：特定的錯誤處理
    fun processDataSafe(data: List<DataItem>): Result<List<ProcessedItem>> {
        return try {
            val result = data.map { item ->
                heavyProcessing(item)
            }
            Result.success(result)
        } catch (e: IllegalArgumentException) {
            Result.failure(ValidationException("無效的資料格式", e))
        } catch (e: Exception) {
            Result.failure(ProcessingException("處理資料失敗", e))
        }
    }
    
    // 陷阱 3：未處理協程例外
    suspend fun processAsyncData(): List<DataItem> {
        val results = coroutineScope {
            val data1 = async { fetchData1() }
            val data2 = async { fetchData2() }
            listOf(data1.await(), data2.await())
        }
        return results.flatten()
        // 如果任何協程失敗，整個操作都會失敗
    }
    
    // 解決方案：正確處理協程例外
    suspend fun processAsyncDataSafe(): List<DataItem> {
        return try {
            coroutineScope {
                val data1 = async { fetchData1() }
                val data2 = async { fetchData2() }
                listOf(data1.await(), data2.await())
            }.flatten()
        } catch (e: Exception) {
            // 處理特定的例外
            when (e) {
                is NetworkException -> handleNetworkError(e)
                is TimeoutException -> handleTimeoutError(e)
                else -> throw ProcessingException("處理非同步資料失敗", e)
            }
            emptyList()
        }
    }
    
    // 陷阱 4：不一致的錯誤型別
    fun validateUser(user: User) {
        if (user.name.isBlank()) {
            throw "Name is required"
        }
        if (user.email.isBlank()) {
            throw ValidationException("Email is required")
        }
        // 混合的錯誤型別
    }
    
    // 解決方案：使用密封類別表示錯誤型別
    sealed class ValidationError : Exception() {
        object MissingName : ValidationError()
        object MissingEmail : ValidationError()
        object InvalidEmail : ValidationError()
    }
    
    fun validateUserSafe(user: User): Result<User> {
        return when {
            user.name.isBlank() -> Result.failure(ValidationError.MissingName)
            user.email.isBlank() -> Result.failure(ValidationError.MissingEmail)
            !isValidEmail(user.email) -> Result.failure(ValidationError.InvalidEmail)
            else -> Result.success(user)
        }
    }
    
    // 陷阱 5：未提供上下文
    suspend fun updateUser(userId: Long, data: UpdateUserRequest): User {
        return try {
            val response = httpClient.put("/api/users/$userId") {
                setBody(Json.encodeToString(data))
            }
            Json.decodeFromString(response)
        } catch (e: Exception) {
            throw Exception("Update failed")
            // 遺失了原始錯誤上下文
        }
    }
    
    // 解決方案：保留錯誤上下文
    suspend fun updateUserSafe(userId: Long, data: UpdateUserRequest): User {
        return try {
            val response = httpClient.put("/api/users/$userId") {
                setBody(Json.encodeToString(data))
            }
            Json.decodeFromString(response)
        } catch (e: Exception) {
            throw UserUpdateException("更新使用者 $userId 失敗", e)
        }
    }
}

// 用於更好錯誤處理的自訂例外
class DataFetchException(message: String, cause: Throwable? = null) : 
    Exception(message, cause)

class ValidationException(message: String, cause: Throwable? = null) : 
    Exception(message, cause)

class ProcessingException(message: String, cause: Throwable? = null) : 
    Exception(message, cause)

class NetworkException(message: String, cause: Throwable? = null) : 
    Exception(message, cause)

class UserUpdateException(message: String, cause: Throwable? = null) : 
    Exception(message, cause)

// 錯誤處理最佳實踐
class ErrorHandlingBestPractices {
    
    // 1. 對可能失敗的操作使用 Result 型別
    fun divide(a: Int, b: Int): Result<Int> {
        return if (b != 0) {
            Result.success(a / b)
        } else {
            Result.failure(ArithmeticException("Division by zero"))
        }
    }
    
    // 2. 使用密封類別表示錯誤型別
    sealed class ApiError : Exception() {
        object NetworkError : ApiError()
        object ServerError : ApiError()
        data class ValidationError(val field: String) : ApiError()
    }
    
    // 3. 使用帶特定例外型別的 try-catch
    fun processData(data: String): Result<ProcessedData> {
        return try {
            val processed = heavyProcessing(data)
            Result.success(processed)
        } catch (e: IllegalArgumentException) {
            Result.failure(ApiError.ValidationError("Invalid data format"))
        } catch (e: Exception) {
            Result.failure(ApiError.ServerError)
        }
    }
    
    // 4. 使用協程例外處理器
    private val exceptionHandler = CoroutineExceptionHandler { _, exception ->
        when (exception) {
            is NetworkException -> handleNetworkError(exception)
            is TimeoutException -> handleTimeoutError(exception)
            else -> handleGenericError(exception)
        }
    }
    
    // 5. 對獨立操作使用 supervisorScope
    suspend fun processIndependentData(): List<DataItem> {
        return supervisorScope {
            val data1 = async { fetchData1() }
            val data2 = async { fetchData2() }
            
            // 如果一個失敗，其他繼續
            listOfNotNull(data1.awaitOrNull(), data2.awaitOrNull())
        }
    }
}
```
</UniversalEditor>

## 總結

在本模組中，我們探討了 Kotlin 開發中的常見陷阱及其解決方案。以下是關鍵要點：

### 涵蓋的關鍵概念
1. **協程編程陷阱**：結構化並行、取消和適當的錯誤處理
2. **空安全問題**：安全呼叫運算子、Elvis 運算子和智慧轉換
3. **效能優化錯誤**：高效的集合操作、快取和背景處理
4. **記憶體管理問題**：資源清理、弱引用和物件池
5. **錯誤處理錯誤**：自訂例外、Result 型別和適當的錯誤上下文

### 常見陷阱與解決方案

| 陷阱類別 | 常見錯誤 | 解決方案 |
|-----------------|----------------|----------|
| **協程** | 未使用結構化並行 | 使用 coroutineScope 和 supervisorScope |
| **空安全** | 不安全的 null 存取 | 使用安全呼叫運算子 (?.) 和 Elvis 運算子 (?:) |
| **效能** | 低效的集合操作 | 使用序列和適當的資料結構 |
| **記憶體** | 資源洩漏 | 使用 use 函式和適當的清理 |
| **錯誤處理** | 吞掉例外 | 使用自訂例外和 Result 型別 |

### 最佳實踐
1. **使用結構化並行**：始終使用 coroutineScope 進行適當的生命週期管理
2. **安全處理 Null**：使用安全呼叫運算子並提供有意義的預設值
3. **優化效能**：對大型集合使用序列並使用適當的調度器
4. **管理記憶體**：在適當時清理資源並使用弱引用
5. **正確處理錯誤**：使用自訂例外並保留錯誤上下文
6. **徹底測試**：為邊緣情況和錯誤場景編寫測試
7. **監控效能**：使用分析工具識別瓶頸

### 下一步
在下一個模組中，我們將探討 Kotlin 的慣用模式和效能優化技術，重點是編寫乾淨、高效和可維護的 Kotlin 程式碼。

---

**實踐挑戰**：重構一個有問題的程式碼庫以修復常見的陷阱，包括空安全問題、協程問題、記憶體洩漏和糟糕的錯誤處理。實現適當的解決方案並編寫全面的測試。
